module mod_odepack

   use petsc_wrapper
   use mod_ode_solver
   use stdlib_string_type
   use stdlib_strings

   implicit none

   private
   public :: type_ode_solver

   type :: type_ode_solver
      character(len=:), allocatable :: scheme
      class(type_ode_solver_abstract), allocatable :: ode_solver
      integer :: step_number
   contains

      procedure :: create => CreateOdeSolver
      procedure :: set_step_number => SetStepNumber
      procedure :: get_step_number => GetStepNumber
      procedure :: destroy => DestroyOdeSolver

   end type type_ode_solver

contains

   subroutine SetStepNumber(this, step_number)
      class(type_ode_solver), intent(inout) :: this
      integer, intent(in) :: step_number

      this%step_number = step_number

   end subroutine SetStepNumber

   integer function GetStepNumber(this) result(step_number)
      class(type_ode_solver), intent(in) :: this

      step_number = this%step_number

   end function GetStepNumber

   subroutine CreateOdeSolver(this, scheme)
      class(type_ode_solver), intent(inout) :: this
      character(len=*), intent(in) :: scheme

      integer :: iloc

      iloc = find(string_type(scheme), "_")

      this%scheme = slice(scheme, 1, iloc - 1)
      select case (this%scheme)
      case ("rk")
         allocate (type_ode_rk :: this%ode_solver)
         call this%ode_solver%initialize(slice(scheme, first=iloc + 1))
      case ("euler")
         allocate (type_ode_euler :: this%ode_solver)
         call this%ode_solver%initialize(slice(scheme, first=iloc + 1))
      case default
         call petsc_error_print("unknown ode solver "//scheme//".")
      end select

   end subroutine CreateOdeSolver

   subroutine DestroyOdeSolver(this)
      class(type_ode_solver), intent(inout) :: this

      call this%ode_solver%destroy()
      deallocate (this%ode_solver)
      deallocate (this%scheme)

   end subroutine DestroyOdeSolver

end module mod_odepack
